mod imp{
    use glib::{ParamFlags, ParamSpec, Value,ParamSpecString,ParamSpecBoolean};
    use gtk::glib;
    use gtk::prelude::*;
    use gtk::subclass::prelude::*;

    use once_cell::sync::Lazy;
    use std::cell::RefCell;
    use std::rc::Rc;

    use super::TodoData;

    // ANCHOR: struct_and_subclass
    // Object holding the state
    #[derive(Default)]
    pub struct TodoObject {
        pub data: Rc<RefCell<TodoData>>,
    }

    // The central trait for subclassing a GObject
    #[glib::object_subclass]
    impl ObjectSubclass for TodoObject {
        const NAME: &'static str = "TodoObject";
        type Type = super::TodoObject;
        type ParentType = glib::Object;
    }
    // ANCHOR_END: struct_and_subclass

    // Trait shared by all GObjects
    impl ObjectImpl for TodoObject {
        fn properties() -> &'static [ParamSpec] {
            static PROPERTIES: Lazy<Vec<ParamSpec>> = Lazy::new(|| {
                vec![
                    ParamSpecBoolean::new(
                        // Name
                        "completed",
                        // Nickname
                        "completed",
                        // Short description
                        "completed",
                        // Default value
                        false,
                        // The property can be read and written to
                        ParamFlags::READWRITE,
                    ),
                    ParamSpecString::new(
                        // Name
                        "content",
                        // Nickname
                        "content",
                        // Short description
                        "content",
                        // Default value
                        None,
                        // The property can be read and written to
                        ParamFlags::READWRITE,
                    ),
                ]
            });
            PROPERTIES.as_ref()
        }

        fn set_property(&self, _obj: &Self::Type, _id: usize, value: &Value, pspec: &ParamSpec) {
            match pspec.name() {
                "completed" => {
                    let input_value = value.get().expect("The value needs to be of type `bool`.");
                    self.data.borrow_mut().completed = input_value;
                }
                "content" => {
                    let input_value = value
                        .get()
                        .expect("The value needs to be of type `String`.");
                    self.data.borrow_mut().content = input_value;
                }
                _ => unimplemented!(),
            }
        }

        fn property(&self, _obj: &Self::Type, _id: usize, pspec: &ParamSpec) -> Value {
            match pspec.name() {
                "completed" => self.data.borrow().completed.to_value(),
                "content" => self.data.borrow().content.to_value(),
                _ => unimplemented!(),
            }
        }
    }
}

use glib::Object;
use gtk::glib;

// ANCHOR: glib_wrapper_and_new
glib::wrapper! {
    pub struct TodoObject(ObjectSubclass<imp::TodoObject>);
}

impl TodoObject {
    pub fn new(completed: bool, content: String) -> Self {
        Object::new(&[("completed", &completed), ("content", &content)])
            .expect("Failed to create `TodoObject`.")
    }
}
// ANCHOR_END: glib_wrapper_and_new

// ANCHOR: todo_data
#[derive(Default)]
pub struct TodoData {
    pub completed: bool,
    pub content: String,
}
// ANCHOR: todo_data
